package base.TemplateUse;

import base.CaseCaller.BaseCaseCaller;
import base.CaseCaller.ICaseCaller;
import base.core.TestBase;
import base.token.AbstractFetchToken;
import base.vo.BaseParameter2;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;


/**
 * case的模板方法，使用doIt即可完成一次简单的调用
 * 需要定制的地方可以通过重载的方式进行配置自定义
 * abstract方法的目的就是通过实现他来添加@Test注解
 * 同时可以固定外部调用doIt的时候固定参数位置
 *
 * @construct 无参构造将会使用默认的configureProperty
 *            来配置用户和不使用统一的baseHost地址
 *            可以通过配置来指定【账户】【host]数据
 * @field token 这个是账户token，不指定则会使用configure中的默认账号
 */

public abstract class BaseTemplate2 extends TestBase {
    public Logger logger = LogManager.getLogger();

    public void testUseDemo(){
        List<String> demoList = new ArrayList<>();
        demoList.add("以下将展示整个模板的调用顺序");
        demoList.add("1.首先，继承类必须实现方法：testCase，并在此方法上面添加@Test(dataProvider = \"data\"), 加上这个注解我就可以给他提供数据了");
        demoList.add("2.继承类直接调用doIt就行");
        demoList.add("3.doIt内部执行流程");
        demoList.add("4.doSomethingBeforeCall  调用接口前准备");
        demoList.add("5.call  调用接口");
        demoList.add("6.doSomethingAfterCall   调用接口后操作");
        demoList.add("7.judgeSuccess   与期望进行判断( 可自定义判断)");
        demoList.add("8.analyzers   自定义方法操作（函数指针）");
    }

    protected List<ICaseCaller> caseCallerListFactory(List<BaseParameter2> bp2List){
        return bp2List.stream().map(x -> new BaseCaseCaller(x)).collect(Collectors.toList());
    }

    @Setter
    AbstractFetchToken fetchToken;

    //保存每次返回的结果
    @Getter
    final private List<String> stepResults = new ArrayList<>();

    //子类看需求重弄下
    protected void createToken(){fetchToken = null;}

    //根据fetchToken实现自定义获取token
    private String getToken(){
        return fetchToken == null ? "" : fetchToken.getToken();
    }

    //打印用例序号
    protected void showStep(String comment) {
        logger.info("测试用例：" + comment + " 开始执行");
    }

    //展示入参
    protected void showParameter(JSONObject formBody) {
        logger.info("form入参：" + formBody);
    }

    public void doIt(List<ICaseCaller> caseCallers, String comment) {
        doIt(caseCallers, comment, null);
    }

    /**
     * 执行测试用例
     *
     * @param caseCallers 一个list代表一个完整吃测试用例
     * @param comment           本用例的描述
     * @param register          如果需要定时查看，则通过这个接口去注册
     */
    public void doIt(List<ICaseCaller> caseCallers, String comment, Supplier register) {
        stepResults.clear();
        createToken();
        String token = getToken();
        //调用前最后一次修改case的机会
        doSomethingBeforeGlobal(caseCallers);

        for (int i = 0; i < caseCallers.size(); ++i) {
            ICaseCaller callser = caseCallers.get(i);
            logger.info("执行用例: " + comment + " 第" + (i + 1) + "/" + caseCallers.size() + "步开始");
            showStep(callser.getBaseParameter().getStep());
            showParameter(callser.getBaseParameter().getRequest());


            callser.doSomethingBeforeCall();
            logger.info("准备开始调用");
            String responseBody = callser.call(token);
            logger.info("调用完成，返回值为: " + responseBody);
            responseBody = callser.doSomethingAfterCall(responseBody);

            stepResults.add(responseBody);
            callser.setResponse(responseBody);

            //判断是否返回的code为和期望一致
            boolean willEnd = true;
            willEnd = callser.judgeSuccess(responseBody);

            if (willEnd)
                logger.info("执行用例: " + comment + " 第" + (i + 1) + "/" + caseCallers.size() + "步成功");
            else {
                logger.error("执行用例: " + comment + " 第" + (i + 1) + "/" + caseCallers.size() + "步失败!执行结束！");
                break;
            }

            //将前一步的返回值交给和某一步进行修改
            callser.dataExchangeFromPre(responseBody, caseCallers.get(callser.getWillIndex()).getBaseParameter());
        }
        //调用完之后最后一次修改的机会
        doSomethingAfterGlobal(caseCallers);

        if (register != null && (boolean) register.get()) {
            logger.info("已将定时查看信息提交");
        }

        logger.info("用例" + comment + "执行完成\n");
    }

//
//    // 在调用前对参数的调整如加入验签
//    protected void doSomethingBeforeCall(Map<String, Object> map){}
//    // 如在调用后需要解密啥的呢
//    protected String doSomethingAfterCall(String response){return response;}
//

    // 全局的调用前置/后置操作
    public void doSomethingBeforeGlobal(List<ICaseCaller> obj){}
    public void doSomethingAfterGlobal(List<ICaseCaller> obj){}

//    protected String call(EnumRequestMethod method, String url, String accessToken, Map<String, Object> map, Map<String, String> headers, Object... objs) {
//       return null;
//    }
//

    /**
     *
     * 目的就是为了在实现类中写这个东西@Test(dataProvider = "data")统一调用
     * @param comment
     * @param parameterList
     */
    public abstract void testCase(String comment, List<BaseParameter2> parameterList);
}
